/* eslint-disable promise/always-return */
/* eslint-disable no-console */
const express = require('express');
const fs = require('fs-extra');
const bodyParser = require('body-parser');
const path = require('path');
const multer = require('multer');
const ffmpeg = require('fluent-ffmpeg');

const app = express();
const FileType = require('file-type');
const glob = require('glob');

const UPLOAD_DIR = path.resolve(__dirname, 'uploads');
const TEMP_DIR = path.resolve(__dirname, 'tmp');

app.use('/public', express.static('uploads'));

fs.ensureDirSync(UPLOAD_DIR);
fs.ensureDirSync(TEMP_DIR);

// 配置 multer 存储
const storage = multer.diskStorage({
  destination(req, file, cb) {
    const { identifier } = req.body;
    const chunkDir = path.resolve(TEMP_DIR, identifier);
    // 确保目录存在
    const dir = chunkDir;
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir);
    }
    cb(null, dir);
  },
  filename(req, file, cb) {
    const { identifier, index } = req.body;
    // 设置文件名
    cb(null, `${identifier}-${index}${path.extname(file.originalname)}`);
  },
});
const upload = multer({ storage });

app.post('/upload', bodyParser.raw({ limit: '10mb' }), (req, res) => {
  const chunk = req.body;
  const { identifier, index } = req.query;
  console.log(`identifier ${identifier}, receive chunk index-${index}`);
  const chunkDir = path.resolve(TEMP_DIR, identifier);
  fs.ensureDirSync(chunkDir);
  fs.writeFileSync(`${chunkDir}/${identifier}-${index}`, chunk);
  res.send(
    JSON.stringify({
      tempFilePath: `${identifier}-${index}`,
    })
  );
});

app.post('/upBigFile', upload.single('file'), (req, res) => {
  // 文件上传成功
  res.status(200).json({
    message: 'File uploaded successfully',
  });
});

const mergeFiles = (chunkFilePaths, writeStream) =>
  new Promise((resolve) => {
    const pipeStream = () => {
      if (!chunkFilePaths.length) {
        writeStream.end('done');
        resolve();
        return;
      }
      const filePath = chunkFilePaths.shift();
      const readSteam = fs.createReadStream(filePath);
      readSteam.pipe(writeStream, { end: false });
      readSteam.on('end', () => {
        fs.removeSync(filePath);
        pipeStream();
      });
    };
    pipeStream();
  });

app.get('/merge', async (req, res) => {
  const { identifier } = req.query;
  console.log(`identifier ${identifier}, merge`);
  const chunkDir = path.resolve(TEMP_DIR, identifier);
  const chunkFiles = fs.readdirSync(chunkDir);
  chunkFiles.sort((a, b) => a.split('-')[1] - b.split('-')[1]);
  const chunkFilePaths = chunkFiles.map((fileName) => path.resolve(chunkDir, fileName));

  const targetFilePath = path.resolve(UPLOAD_DIR, identifier);
  const writeStream = fs.createWriteStream(targetFilePath);
  await mergeFiles(chunkFilePaths, writeStream);
  const { ext } = await FileType.fromFile(targetFilePath);
  fs.renameSync(targetFilePath, `${targetFilePath}.${ext}`);
  fs.removeSync(chunkDir);

  res.send(
    JSON.stringify({
      url: `${targetFilePath}.${ext}`,
    })
  );
});

// 视频合并函数
function mergeVideos(segments, output) {
  return new Promise((resolve, reject) => {
    const command = ffmpeg();

    segments.forEach((segment) => {
      command.input(segment);
    });

    command
      .on('end', () => {
        console.log('Video merging finished.');
        resolve();
      })
      .on('error', (err) => {
        console.error('Error:', err);
        reject(err);
      })
      .mergeToFile(output);
  });
}

app.get('/mergeBigFile', async (req, res) => {
  const { identifier } = req.query;
  console.log(`identifier ${identifier}, merge`);
  const chunkDir = path.resolve(TEMP_DIR, identifier);
  const chunkFiles = fs.readdirSync(chunkDir);
  chunkFiles.sort((a, b) => a.split('-')[1] - b.split('-')[1]);
  const chunkFilePaths = chunkFiles.map((fileName) => path.resolve(chunkDir, fileName));

  const targetFilePath = `${path.resolve(UPLOAD_DIR, identifier)}.mp4`;

  console.log(targetFilePath, '====');
  // 合并视频
  mergeVideos(chunkFilePaths, targetFilePath)
    .then(() => {
      // fs.removeSync(chunkDir);
      res.send(JSON.stringify({ url: `${targetFilePath}` }));
    })
    .catch((err) => {
      console.error('Error:', err);
      res.status(500).send('Error merging videos.');
    });
});

app.get('/verify', (req, res) => {
  const { identifier } = req.query;
  console.log(`identifier ${identifier}, verify`);
  const matchs = glob.sync(`${identifier}.*`, { cwd: UPLOAD_DIR });
  if (matchs.length) {
    res.send(
      JSON.stringify({
        needUpload: false,
        url: path.resolve(UPLOAD_DIR, matchs[0]),
      })
    );
  } else {
    const chunkDir = path.resolve(TEMP_DIR, identifier);
    fs.ensureDirSync(chunkDir);
    const chunkFiles = fs.readdirSync(chunkDir);
    res.send(
      JSON.stringify({
        needUpload: true,
        uploadedChunks: chunkFiles.map((fileName) => fileName.split('-')[1] * 1),
      })
    );
  }
});

const server = app.listen(3000, () => {
  const host = server.address().address;
  const { port } = server.address();
  console.log('应用实例，访问地址为 http://%s:%s', host, port);
});
